package com.joinway.extension.socket.server.codec;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.joinway.extension.socket.bean.OutputFrameSegmentConfig;
import com.joinway.extension.socket.serializer.ISegmentSerializer;
import com.joinway.extension.socket.serializer.StringSerializer;

public abstract class AbstractFrameDataEncoder extends ProtocolEncoderAdapter {

	private final static Logger log = LoggerFactory.getLogger(AbstractFrameDataEncoder.class);
	
	protected abstract List<OutputFrameSegmentConfig> getOutputFrameSegmentConfig();
	
	protected abstract int getTotalByteCount();
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
		IoBuffer buffer = IoBuffer.allocate(getTotalByteCount(), false);
		buffer.setAutoExpand(true);
		
		List<OutputFrameSegmentConfig> configs = getOutputFrameSegmentConfig();
		for(OutputFrameSegmentConfig config : configs){
			Object value = getFieldValue(message, config.getField());
			
//			log.debug("encoded value is {}", value);
			
			ISegmentSerializer serializer = config.getSerializer() != null ? config.getSerializer() : getDefaultSerializer();
			byte[] data = serializer.serialize(value);
			buffer.put(data);
		}
		
		buffer.flip();
		out.write(buffer);
	}

	public Object getFieldValue(Object target, String fieldName) throws Exception {
		String methodName = "get" + StringUtils.capitalize(fieldName);
		return MethodUtils.invokeMethod(target, methodName, (Object[])null);
	}
	
	@SuppressWarnings("rawtypes")
	protected ISegmentSerializer getDefaultSerializer(){
		return StringSerializer.Instance;
	}
}
